/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */

package lime2;

import lights.interfaces.*;

/**
 * Models a reaction. Application programmers must be very careful about
 * consequences of the behavior they are trying to implement. Badly written
 * reactions or unexpected interactions between reactions can make the (whole)
 * Lime system to loop: i.e., a a once-per-tuple reaction that "outs" a new
 * tuple for every new tuple that is "outed" in the tuplespace. <br>
 * Please note that the public constructor of Reaction performs parameter
 * checking.
 * 
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini
 */

public class Reaction implements java.io.Serializable {
	/**
	 * The reaction is fired once and then it is removed automatically from the
	 * reactive program.
	 */
	public static final byte ONCE = 1;

	/**
	 * The reaction is fired, and will never fire again for that given tuple,
	 * but remains registered. So, if multiple tuples enable the reaction, the
	 * reaction is fired for each of them.
	 */
	public static final byte ONCEPERTUPLE = 2;

	// is it a once or once-per-tuple reaction ?
	private byte mode;

	/**
	 * The default reaction type is OUT.
	 * 
	 */
	private ReactionType type = ReactionType.Out;

	// the reaction listener of this reaction
	private ReactionListener listener;

	// the template that triggers the firing of this reaction
	private ITuple template;

	/**
	 * Constructor method. Performs parameter checking.
	 * 
	 * @param mode
	 *            Reaction.ONCE or Reaction.ONCEPERTUPLE
	 * @param limetemplate
	 *            the template that triggers the firing of this reaction
	 * @param listener
	 *            the listener which is invoked on firing
	 */
	public Reaction(byte mode, LimeTemplate limetemplate,
			ReactionListener listener) {
		// parameter checking
		if (((mode != ONCE) && (mode != ONCEPERTUPLE)) || limetemplate == null
				|| listener == null)
			throw new IllegalArgumentException("invalid/null value");

		this.mode = mode;
		this.template = limetemplate.limify();
		this.listener = listener;
	}

	public Reaction(byte mode, ReactionType type, LimeTemplate limetemplate,
			ReactionListener listener) {
		this(mode, limetemplate, listener);
		this.type = type;
	}

	Reaction(byte mode, ReactionType type, ITuple template,
			ReactionListener listener) {
		this(mode, template, listener);
		this.type = type;
	}

	/**
	 * Constructor method (package-only visible).
	 * 
	 * @param mode
	 *            Reaction.ONCE or Reaction.ONCEPERTUPLE
	 * @param template
	 *            the "limified" ITuple that triggers the firing of this
	 *            reaction
	 * @param listener
	 *            the listener which is invoked on firing
	 */
	Reaction(byte mode, ITuple template, ReactionListener listener) {
		this.mode = mode;
		this.template = template;
		this.listener = listener;
	}

	/**
	 * Returns the firing mode.
	 * 
	 * @return Reaction.ONCE or Reaction.ONCEPERTUPLE
	 */
	public byte getMode() {
		return mode;
	}

	/**
	 * Returns the template (in form of ITuple) that triggers the firing of this
	 * reaction.
	 * 
	 * @return template ITuple
	 */
	ITuple getTemplate() {
		return template;
	}

	/**
	 * Returns the template (in form of LimeTemplate) that triggers the firing
	 * of this reaction.
	 * 
	 * @return template LimeTemplate
	 */
	public LimeTemplate getLimeTemplate() {
		return LimeTemplate.delimify(template);
	}

	/**
	 * Returns the listener associated with this reaction.
	 * 
	 * @return ReactionListener
	 */
	public ReactionListener getListener() {
		return listener;
	}

	/**
	 * toString method.
	 * 
	 * @return textual representation of a reaction
	 */
	public String toString() {
		String msg = "[Reaction] type=" + type + " mode=";
		switch (mode) {
		case ONCE:
			msg = msg + "ONCE";
			break;
		case ONCEPERTUPLE:
			msg = msg + "ONCEPERTUPLE";
			break;
		}
		return msg + " template=" + template + " listener="
				+ listener.getClass().getName();
	}

	public ReactionType getType() {
		return type;
	}

	public byte getTypeConstant() {
		switch (type) {
		case In:
			return LimeConstants.IN;
		case Rd:
			return LimeConstants.RD;
		case Out:
			return LimeConstants.OUT;
		default: return LimeConstants.OUT;
//			throw new IllegalArgumentException;
		}
	}

}
